#include <GL/glew.h>
#include <GL/glut.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/freeglut.h>
#include <iostream>
#include <stdio.h>
#include <unistd.h>
#include <cmath>
#include <cstdlib>
#include <string.h>
#include <assert.h>
#include <math.h>
#include "CInitGL.h"
#include "math_3d.h"
#include "CShaders.h"
#include "CPipeline.h"


#define WINDOW_WIDTH 1024
#define WINDOW_HEIGHT 768


GLuint CInitGL::gScaleLocation;
CInitGL *CInitGL::instance = 0;

GLuint CShaders::gWorldLocation;
GLuint CInitGL::VBO;
GLuint CInitGL::IBO;
GLuint CInitGL::gWVPLocation;

float CInitGL::Scale = 0.0f;

void CInitGL::setInstance(CInitGL *framework) {
	instance = framework;
}


void CInitGL::StartInitGL(int argc, char** argv)
    {
        glutInit(&argc,argv);
        glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);
      glutInitWindowSize (WINDOW_WIDTH, WINDOW_HEIGHT);
      glutInitWindowPosition(100,100);
      glutCreateWindow("Sector7_0.5.4");

      InitGlutCallbacks();

      GLenum res = glewInit();
    if (res != GLEW_OK) {
      fprintf(stderr, "Error: '%s'\n", glewGetErrorString(res));
      //return 1;
    }

        glClearColor(0.0f,0.0f,0.0f,0.0f);

        CreateVertexBuffer();
        CreateIndexBuffer();

        CompileShaders();

        glutMainLoop();

    }

void CInitGL::RenderScene()
    {
       glClear(GL_COLOR_BUFFER_BIT);

Scale += 0.1f;

CPipeline p;

    p.Rotate(0.0f, Scale, 0.0f);
    p.WorldPos(0.0f, 0.0f, 3.0f);
    Vector3f CameraPos(0.0f, 0.0f, -3.0f);
    Vector3f CameraTarget(0.0f, 0.0f, 2.0f);
    Vector3f CameraUp(0.0f, 1.0f, 0.0f);
    p.SetCamera(CameraPos, CameraTarget, CameraUp);
    p.SetPerspectiveProj(60.0f, WINDOW_WIDTH, WINDOW_HEIGHT, 1.0f, 100.0f);

    glUniformMatrix4fv(gWVPLocation, 1, GL_TRUE, (const GLfloat*)p.GetTrans());

    glEnableVertexAttribArray(0);
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IBO);

    glDrawElements(GL_TRIANGLES, 12, GL_UNSIGNED_INT, 0);

    glDisableVertexAttribArray(0);
    glutSwapBuffers();
}



void CInitGL::InitGlutCallbacks()
    {
        glutDisplayFunc(RenderScene);
        glutIdleFunc(RenderScene);
    }

void CInitGL::CreateVertexBuffer()
    {
        Vector3f Verticies[4];
        Verticies[0] = Vector3f(-1.0f,-1.0f,0.5773f);
        Verticies[1] = Vector3f(0.0f, -1.0f, -1.15475f);
        Verticies[2] = Vector3f(1.0f, -1.0f, 0.5773f);
        Verticies[3] = Vector3f(0.0f, 1.0f, 0.0f);

        glGenBuffers(1, &VBO);
        glBindBuffer(GL_ARRAY_BUFFER, VBO);
        glBufferData(GL_ARRAY_BUFFER, sizeof(Verticies), Verticies, GL_STATIC_DRAW);

    }


void CInitGL::CreateIndexBuffer()
    {
      unsigned int Indices[] = {
                                    0, 3, 1,
                                    1, 3, 2,
                                    2, 3, 0,
                                    0, 2, 1
                                            };
        glGenBuffers(1, &IBO);
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IBO);
        glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(Indices), Indices, GL_STATIC_DRAW);
    }
